home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / libraries / string-ext / conversions.dylan < prev    next >
Encoding:
Text File  |  1995-03-15  |  5.4 KB  |  191 lines  |  [TEXT/ttxt]

  1. module:     string-conversions
  2. author:     Nick Kramer (nkramer@cs.cmu.edu)
  3. synopsis:   Convert strings to numbers and numbers to strings.
  4. copyright:  Copyright (C) 1994, Carnegie Mellon University.
  5.             All rights reserved.
  6. rcs-header: $Header: conversions.dylan,v 1.2 94/12/10 15:40:59 nkramer Exp $
  7.  
  8. //======================================================================
  9. //
  10. // Copyright (c) 1994  Carnegie Mellon University
  11. // All rights reserved.
  12. // 
  13. // Use and copying of this software and preparation of derivative
  14. // works based on this software are permitted, including commercial
  15. // use, provided that the following conditions are observed:
  16. // 
  17. // 1. This copyright notice must be retained in full on any copies
  18. //    and on appropriate parts of any derivative works.
  19. // 2. Documentation (paper or online) accompanying any system that
  20. //    incorporates this software, or any part of it, must acknowledge
  21. //    the contribution of the Gwydion Project at Carnegie Mellon
  22. //    University.
  23. // 
  24. // This software is made available "as is".  Neither the authors nor
  25. // Carnegie Mellon University make any warranty about the software,
  26. // its performance, or its conformity to any specification.
  27. // 
  28. // Bug reports, questions, comments, and suggestions should be sent by
  29. // E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  30. //
  31. //======================================================================
  32.  
  33.  
  34. define method as (the-class == <string>, c :: <character>)
  35.     => c :: <string>;
  36.   make(<string>, size: 1, fill: c);
  37. end method as;
  38.  
  39.  
  40. // Either returns or forces an error.
  41. //
  42. define method check-base (base :: <integer>) => ();
  43.   if (base < 2 | base > 36)
  44.     error("%d is not a legal base.", base);
  45.   end if;
  46. end method check-base;
  47.  
  48.  
  49. // Integer-to-string checks a few special cases, and lets
  50. // positive-integer-to-string do the real work.
  51. //
  52. define method integer-to-string (num :: <integer>, 
  53.                  #key base = 10,
  54.                  uppercase = #f)
  55.     => number :: <string>;
  56.   check-base(base);
  57.   if (num = 0)
  58.     "0";
  59.   elseif (num < 0)
  60.     concatenate("-", positive-integer-to-string(- num, base, uppercase));
  61.   else
  62.     positive-integer-to-string(num, base, uppercase);
  63.   end if;
  64. end method integer-to-string;
  65.  
  66.  
  67. define method positive-integer-to-string (num :: <integer>, 
  68.                       base :: <integer>,
  69.                       uppercase)
  70.     => number :: <string>;
  71.   if (num = 0)
  72.     "";
  73.   else
  74.     let low-digit = modulo(num, base);
  75.     add-last(positive-integer-to-string(truncate/(num, base), base, uppercase),
  76.          integer-to-digit(low-digit, base: base, uppercase: uppercase));
  77.   end if;
  78. end method positive-integer-to-string;
  79.  
  80.  
  81. // Converts an integer into a character.  Bases beyond 36 probably
  82. // don't come out very well, however.
  83. //
  84. define method integer-to-digit (integer :: <integer>,
  85.                 #key base = 10,
  86.                 uppercase = #f)
  87.     => digit :: <character>;
  88.   check-base(base);
  89.   if (integer < 0   |   integer >= base)
  90.     error("%d isn't a digit in base %d", integer, base);
  91.   end if;
  92.  
  93.   select (integer)
  94.     0 => '0';
  95.     1 => '1';
  96.     2 => '2';
  97.     3 => '3';
  98.     4 => '4';
  99.     5 => '5';
  100.     6 => '6';
  101.     7 => '7';
  102.     8 => '8';
  103.     9 => '9';
  104.     otherwise =>
  105.       as(<character>, 
  106.      integer - 10 + as(<integer>, if (uppercase) 'A' else 'a' end));
  107.   end select;
  108. end method integer-to-digit;
  109.  
  110.  
  111. // Interprets the empty string as 0.  This can be either a bug or a
  112. // feature, depending on your viewpoint.
  113. //
  114. // Will signal an error for invalid strings.
  115. //
  116. define method string-to-integer (string :: <sequence>, #key base = 10)
  117.     => int :: <integer>;
  118.   check-base(base);
  119.   let number = 0;
  120.   let sign = if (string[0] == '-')  -1  else  1  end if;
  121.   let start-index = if (sign = -1)  1  else  0  end if;
  122.   for (i from start-index below string.size)
  123.     let digit = digit-to-integer(string[i]);
  124.     if (digit >= base)
  125.       error("\"%s\" isn't in base %d\n", string, base);
  126.     else
  127.       number := number * base  + digit;
  128.     end if;
  129.   end for;
  130.   sign * number;
  131. end method string-to-integer;
  132.  
  133.  
  134. define method digit-to-integer (c :: <character>) => digit :: <integer>;
  135.   if (~alphanumeric?(c))
  136.     error("Invalid digit %=", c);
  137.   end if;
  138.   select (c)
  139.     '0' => 0;
  140.     '1' => 1;
  141.     '2' => 2;
  142.     '3' => 3;
  143.     '4' => 4;
  144.     '5' => 5;
  145.     '6' => 6;
  146.     '7' => 7;
  147.     '8' => 8;
  148.     '9' => 9;
  149.     otherwise =>
  150.       as(<integer>, as-lowercase(c)) - as(<integer>, 'a') + 10;
  151.   end select;
  152. end method digit-to-integer;
  153.  
  154.  
  155. // Returns a number.  Hopefully it'll return an integer when
  156. // appropriate and a float at other times, but I'm not real sure.
  157. //
  158. // Has no problem accepting strings with multiple decimal points.
  159. // Decimal points beyond the first one are ignored, though.
  160. // Similarly, there can be any number of + or - in the string (and not
  161. // just at the beginning), with the last one determining whether the
  162. // number is positive or negative.
  163. //
  164. define method string-to-number (string :: <sequence>, #key base: base = 10)
  165.     => num :: <number>;
  166.   let number = 0;
  167.   let negate = 1;
  168.   let seen-decimal = #f;
  169.   let decimal-divisor = 1;
  170.   for (c in string)
  171.     select (c)
  172.       '-' =>      negate := -1;
  173.       '+' =>      negate := 1;
  174.       '.' =>      seen-decimal := #t;
  175.       otherwise =>
  176.     let digit = digit-to-integer(c);
  177.     if (digit >= base) 
  178.       error("\"%s\" isn't in base %d\n", string, base);
  179.     elseif (seen-decimal)  
  180.       decimal-divisor := decimal-divisor * base;
  181.       number := number + as(<float>, digit) / as(<float>, decimal-divisor);
  182.     else 
  183.       number := number * base  + digit;
  184.     end if;
  185.     end select;
  186.   end for;
  187.  
  188.   number * negate;
  189. end method string-to-number;
  190.  
  191.